package cn.zyjblogs.starter.common.utils.collect;

import cn.zyjblogs.starter.common.utils.collections.CollectionUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;

public class Lists {

    /**
     * 获取一个空List，这个空List不可变
     *
     * @param <T> 元素类型
     * @return 空的List
     * @see Collections#emptyList()
     */
    public static <T> List<T> empty() {
        return Collections.emptyList();
    }
    /**
     * 通过传入分区长度，将指定列表分区为不同的块，每块区域的长度相同（最后一块可能小于长度）<br>
     * 分区是在原List的基础上进行的，返回的分区是不可变的抽象列表，原列表元素变更，分区中元素也会变更。
     *
     * <p>
     * 需要特别注意的是，此方法调用{@link List#subList(int, int)}切分List，
     * 此方法返回的是原List的视图，也就是说原List有变更，切分后的结果也会变更。
     * </p>
     *
     * @param <T>  集合元素类型
     * @param list 列表，为空时返回{@link #empty()}
     * @param size 每个段的长度，当长度超过list长度时，size按照list长度计算，即只返回一个节点
     * @return 分段列表
     */
    public static <T> List<List<T>> partition(List<T> list, int size) {
        if (CollectionUtils.isEmpty(list)) {
            return empty();
        }

        return (list instanceof RandomAccess)
                ? new RandomAccessPartition<>(list, size)
                : new Partition<>(list, size);
    }

    /**
     * 对集合按照指定长度分段，每一个段为单独的集合，返回这个集合的列表
     *
     * <p>
     * 需要特别注意的是，此方法调用{@link List#subList(int, int)}切分List，
     * 此方法返回的是原List的视图，也就是说原List有变更，切分后的结果也会变更。
     * </p>
     *
     * @param <T>  集合元素类型
     * @param list 列表，为空时返回{@link #empty()}
     * @param size 每个段的长度，当长度超过list长度时，size按照list长度计算，即只返回一个节点
     * @return 分段列表
     * @see #partition(List, int)
     */
    public static <T> List<List<T>> split(List<T> list, int size) {
        return partition(list, size);
    }
    /**
     * 将集合平均分成多个list，返回这个集合的列表
     * <p>例：</p>
     * <pre>
     *     ListUtil.splitAvg(null, 3);	// []
     *     ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 2);	// [[1, 2], [3, 4]]
     *     ListUtil.splitAvg(Arrays.asList(1, 2, 3), 5);	// [[1], [2], [3], [], []]
     *     ListUtil.splitAvg(Arrays.asList(1, 2, 3), 2);	// [[1, 2], [3]]
     * </pre>
     *
     * @param <T>   集合元素类型
     * @param list  集合
     * @param limit 要均分成几个list
     * @return 分段列表
     * @author lileming
     */
    public static <T> List<List<T>> splitAvg(List<T> list, int limit) {
        if (CollectionUtils.isEmpty(list)) {
            return empty();
        }

        return (list instanceof RandomAccess)
                ? new RandomAccessAvgPartition<>(list, limit)
                : new AvgPartition<>(list, limit);
    }

    /**
     * 将指定元素交换到指定索引位置,其他元素的索引值不变<br>
     * 交换会修改原List<br>
     * 如果集合中有多个相同元素，只交换第一个找到的元素
     *
     * @param <T>         元素类型
     * @param list        列表
     * @param element     需交换元素
     * @param targetIndex 目标索引
     */
    public static <T> void swapTo(List<T> list, T element, Integer targetIndex) {
        if (CollectionUtils.isNotEmpty(list)) {
            final int index = list.indexOf(element);
            if (index >= 0) {
                Collections.swap(list, index, targetIndex);
            }
        }
    }

    /**
     * 将指定元素交换到指定元素位置,其他元素的索引值不变<br>
     * 交换会修改原List<br>
     * 如果集合中有多个相同元素，只交换第一个找到的元素
     *
     * @param <T>           元素类型
     * @param list          列表
     * @param element       需交换元素
     * @param targetElement 目标元素
     */
    public static <T> void swapElement(List<T> list, T element, T targetElement) {
        if (CollectionUtils.isNotEmpty(list)) {
            final int targetIndex = list.indexOf(targetElement);
            if (targetIndex >= 0) {
                swapTo(list, element, targetIndex);
            }
        }
    }
}
